package com.ls.fw.data.statement;

import java.io.Closeable;
import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import com.ls.fw.data.bean.Column;
import com.ls.fw.data.bean.From;
import com.ls.fw.data.bean.Group;
import com.ls.fw.data.bean.MethodField;
import com.ls.fw.data.bean.MethodOrder;
import com.ls.fw.data.bean.Order;
import com.ls.fw.data.bean.Order.OrderType;
import com.ls.fw.data.bean.SortFunctions;
import com.ls.fw.data.bean.Table;
import com.ls.fw.data.enums.AFunctions;
import com.ls.fw.data.enums.JoinType;
import com.ls.fw.data.visitor.FieldVisitor;
import com.ls.fw.data.visitor.StatementVisitor;

/**
 * 搜索信息实体
 * @author ls
 * 2014年11月21日下午2:34:54
 */
public class Select extends BaseWhere implements Serializable,Closeable,Statement{

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	
	private List<Column> columns = new ArrayList<Column>();
	private List<Group> groupBys = new ArrayList<Group>();
	private List<Order> orderBys = new ArrayList<Order>();
	private int offset = 0;
	private int page = 1;
	private int rowCount = -1;

	public boolean isQuery = false;
	
	/**
	 * 是否存在聚合函数
	 */
	public boolean isAgg = false;
	
	/**
	 * 是否分组
	 */
	public boolean isGroup = false;
	
	public boolean fullTextQuery = true;
	
	public boolean high = false;
	
	public Select() {
	}

	
	public void addGroupBy(String name) {
		this.addGroupBy(new Group(name));
	}

	public void addGroupBy(Group field) {
		isGroup = true;
		this.groupBys.add(field);
	}
	
	public void addOrderBy(String name, String type) {
		this.addOrderBy(name, OrderType.get(type));
	}


	/**
	 * 添加一个降序排序条件
	 * @author ls
	 * 2014年11月22日下午4:31:21 
	 * @param name
	 */
	public void addOrderBy(String name) {
		this.addOrderBy(name, OrderType.DESC);
	}
	
	
	public void addOrderBy(String name, OrderType type) {
		if ("_score".equals(name)) {
			isQuery = true;
		}
		this.orderBys.add(new Order(name, type));
	}

	
	/**
	 * 排序方法
	 * @author ls
	 * 2014年11月26日下午12:30:21 
	 * @param name
	 * @param type
	 * @return
	 */
	public MethodOrder addMethodOrderBy(String name, OrderType type) {
		MethodOrder m = new MethodOrder(name, type);
		this.orderBys.add(m);
		return m;
	}
	
	public MethodOrder addMethodOrderBy(SortFunctions sf, OrderType type) {
		MethodOrder m = new MethodOrder(sf, type);
		this.orderBys.add(m);
		return m;
	}
	
	
	/**
	 * 排序方法
	 * @author ls
	 * 2014年11月26日下午12:31:30 
	 * @param name
	 * @param type
	 * @return
	 */
	public MethodOrder addMethodOrderBy(String name, String type) {
		MethodOrder m = new MethodOrder(name, OrderType.get(type));
		this.orderBys.add(m);
		return m;
	}
	
	public MethodOrder addMethodOrderBy(SortFunctions sf, String type) {
		MethodOrder m = new MethodOrder(sf, OrderType.get(type));
		this.orderBys.add(m);
		return m;
	}
	
	
	/**
	 * 
	 * @author ls
	 * 2014年12月2日下午2:53:13 
	 * @param af 方法名称
	 * @return
	 */
	public MethodField addMethodField(AFunctions af) {
		MethodField m = new MethodField(af);
		this.addField(m);
		isAgg = true;
		return m;
	}
	
	
	/**
	 * 
	 * @author ls
	 * 2014年12月2日下午2:53:39 
	 * @param name 方法名称
	 * @return
	 */
	public MethodField addMethodField(String name) {
		MethodField m = new MethodField(name);
		this.addField(m);
		isAgg = true;
		return m;
	}
	
	public Column addField(String name) {
		Column f = new Column(name);
		return this.addField(f);
	}
	
	public Column addField(Column column) {
		if (column == null) {
			return column;
		}
		if (column instanceof MethodField) {
			AFunctions af =	AFunctions.get(column.getName());
			switch(af){
				case AVG:
				case COUNT:
				case MAX:
				case MIN:
				case SUM:
					isAgg = true;
					break;
				case UNKWON:
				default:
					return column;
				
			}
		}
		columns.add(column);
		return column;
	}

	
	public List<Column> getFields() {
		return columns;
	}

	public void setOffset(int offset) {
		this.offset = offset;
		int p = offset/rowCount;
		page = p + 1;
	}

	public void setRowCount(int rowCount) {
		this.rowCount = rowCount;
	}

	public List<Group> getGroupBys() {
		return groupBys;
	}

	public List<Order> getOrderBys() {
		return orderBys;
	}

	public int getOffset() {
		return offset;
	}

	public int getRowCount() {
		return rowCount;
	}


	@Override
	public String toString() {
		return "Select [fields=" + columns + ", groupBys="
				+ groupBys + ", orderBys=" + orderBys + ", offset=" + offset
				+ ", rowCount=" + rowCount + ", isQuery=" + isQuery
				+ ", isAgg=" + isAgg + "]"+super.toString();
	}


	@Override
	public void close() throws IOException {
		this.columns.clear();
		this.groupBys.clear();
		this.orderBys.clear();
	}
	
	@Override
	public void accept(StatementVisitor statementVisitor) {
		statementVisitor.visit(this);
	}

	/**
	 * @param from the from to set
	 */
	public void setFrom(From from) {
		this.from = from;
		this.setFieldTable(from.getTable());
	}
	
	/**
	 * @param table the table to set
	 */
	public void addFromItem(Table table) {
		from.addFromItem(table);
		this.setFieldTable(from.getTable());
	}
	
	public void addFromItem(String schemaName, String name) {
		from.addFromItem(schemaName, name);
		this.setFieldTable(from.getTable());
	}
	
	public void addFromItem(String name) {
		from.addFromItem(name);
		this.setFieldTable(from.getTable());
	}
	
	
	public From addFromItem(String table1, JoinType joinType, String table2,
			String table1Field, String table2Field){
		return this.from.addFromItem(table1, joinType, table2, table1Field, table2Field);
	}
	
	
	private void setFieldTable(Table table){
		for (Column column : columns) {
			if(column.getTable()==null){
				column.setTable(table);
			}
		}
	}
	
	public boolean hasOrder(){
		return this.orderBys==null || orderBys.isEmpty()?true:false;
	}


	public int getPage() {
		return page;
	}


	public void setPage(int page) {
		this.page = page;
		if(page > 0){
			this.offset = (page-1)*this.rowCount;
		}
	}
	
	 
	public boolean isShowAll(){
		boolean showAll = (this.columns == null || this.columns.isEmpty());
		if(!showAll && this.columns != null){
			int size = this.columns.size();
			if(size==1){
				Column c =  this.columns.get(0);
				if("*".equals(c.getName())){
					showAll = true;
				}
			}else{
				for (Column c : columns) {
					if("*".equals(c.getName())){
						showAll = true;
						break;
					}
				}
			}
		}
		return showAll;
	}
	
	
	/**
	 * 浏览字段
	 * @author ls
	 * 2014年12月1日上午11:26:49 
	 * @param fieldVisitor
	 */
	public int accept(FieldVisitor fieldVisitor) {
		if(columns != null && !columns.isEmpty()){
			for (Column column : columns) {
				fieldVisitor.visit(column);
			}
			return columns.size();
		}
		return 0;
	}

	
	/**
	 * 是否为求count
	 * 
	 * @author lisheng
	 * @date 2015年1月5日 下午12:57:06
	 * @version V1.0
	 * @return
	 */
	public boolean isCount(){
		boolean flag = false;
		if(columns != null && !columns.isEmpty()){
			for (Column column : columns) {
				 if(column instanceof MethodField){
					 if(column.getName().equalsIgnoreCase(AFunctions.COUNT.getName())){
						 flag = true;
						 break;
					 }
				 }
			}
		}
		return flag;
	}
}
